﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace ReaderWriter.IO
{
    [StructLayout(LayoutKind.Sequential)]
    public struct SHFILEINFO
    {
        public IntPtr hIcon;
        public IntPtr iIcon;
        public uint dwAttributes;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string szDisplayName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
        public string szTypeName;
    }

    class IconExtractor
    {
        public static Dictionary<string, Icon> CachedIcons;
        public const uint SHGFI_ICON = 0x100;
        public const uint SHGFI_LARGEICON = 0x0;
        public const uint SHGFI_SMALLICON = 0x1;
        public const uint SHGFI_OPENICON = 0x2;

        [DllImport("shell32.dll")]
        public static extern IntPtr SHGetFileInfo(string pszPath,
                                    uint dwFileAttributes,
                                    ref SHFILEINFO psfi,
                                    uint cbSizeFileInfo,
                                    uint uFlags);

        [DllImport("user32.dll", SetLastError = true)]
        static extern bool DestroyIcon(IntPtr hIcon);

        public static Icon GetFileIcon(string cFile)
        {   
            SHFILEINFO shi = new SHFILEINFO();
            IntPtr hIcon = SHGetFileInfo(cFile, 0, ref shi, (uint)(Marshal.SizeOf(shi)), SHGFI_SMALLICON | SHGFI_ICON);
            if (shi.hIcon != IntPtr.Zero)
            {
                Icon ret = (Icon)Icon.FromHandle(shi.hIcon).Clone();
                DestroyIcon(shi.hIcon);
                return ret;
            }
            else return null;
        }

        public static Icon GetFolderIcon(string cFolder, bool Open = false)
        {
            SHFILEINFO shi = new SHFILEINFO();
            uint uFlags = SHGFI_SMALLICON | SHGFI_ICON;
            if (Open)
                uFlags |= SHGFI_OPENICON;
            IntPtr hIcon = SHGetFileInfo(cFolder, 0, ref shi, (uint)Marshal.SizeOf(shi), uFlags);
            if (shi.hIcon != IntPtr.Zero)
            {
                Icon ret = (Icon)Icon.FromHandle(shi.hIcon).Clone();
                bool l = DestroyIcon(shi.hIcon);
                return ret;
            }
            else return null;
        }

        
        public static Icon GetIconFromFileExtn(string fileNameWithExtn)
        {
            Icon coolIcon = null;
            if (CachedIcons == null)
            {
                CachedIcons = new Dictionary<string, Icon>();
            }

            if (string.IsNullOrEmpty(fileNameWithExtn) || fileNameWithExtn.EndsWith("\\"))
            {
                if (!CachedIcons.ContainsKey("\\"))
                {
                    CachedIcons.Add("\\", 
                        GetFolderIcon(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)));
                }
                coolIcon = CachedIcons["\\"];
            }
            else
            {   
                string extn = fileNameWithExtn.Substring(fileNameWithExtn.LastIndexOf('.'));
                if (!CachedIcons.ContainsKey(extn))
                {
                    try
                    {
                        string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.InternetCache), Path.GetFileName(fileNameWithExtn));
                        System.IO.File.Create(fileName);
                        CachedIcons.Add(extn,GetFileIcon(fileName));
                    }
                    catch { 
                    }
                }
                coolIcon = CachedIcons[extn];
            }
            return coolIcon;
        }
    }

    internal static class IconUtilities
    {
        [DllImport("gdi32.dll", SetLastError = true)]
        private static extern bool DeleteObject(IntPtr hObject);

        public static ImageSource ToImageSource(this Icon icon)
        {
            if (icon == null)
                return null;
            Bitmap bitmap = icon.ToBitmap();
            IntPtr hBitmap = bitmap.GetHbitmap();

            ImageSource wpfBitmap = Imaging.CreateBitmapSourceFromHBitmap(
                hBitmap,
                IntPtr.Zero,
                Int32Rect.Empty,
                BitmapSizeOptions.FromEmptyOptions());

            if (!DeleteObject(hBitmap))
            {
                throw new Win32Exception();
            }

            return wpfBitmap;
        }
    }
}
